#include "parser.h"
#include "exception.h"
#include "token.h"
#include <cctype>
#include <cstdint>
#include <string>
#include <string_view>
#include "unicode.h"


Parser::Parser(const std::string &file_path, const std::string &source_code,
               Parser *parent, VM *vm)
    : filePath(std::move(file_path)), sourceCode(std::move(source_code)),
      parent(parent), vm(vm) {
  nextCharPtr = sourceCode.cbegin();
  getNextChar();
}
Parser::Parser(std::string &&file_path, std::string &&source_code,
               Parser *parent, VM *vm)
    : filePath(file_path), sourceCode(source_code), parent(parent), vm(vm) {
  nextCharPtr = sourceCode.cbegin();
  getNextChar();
}

auto Parser::getNextChar() noexcept -> void { curChar = *nextCharPtr++; }

auto Parser::getNextToken() noexcept -> void {}

// auto Parser::idOrToken(const std::string& id) noexcept -> TokenType {
auto Parser::idOrToken(std::string_view id) noexcept -> Token::TokenType {
  auto res = keywordsToken.find(id);
  if (res == keywordsToken.end()) {
    return Token::TokenType::ID;
  }
  return res->second;
}

auto Parser::skipBlanks() noexcept -> void {
  while (isspace(curChar)) {
    if (curChar == '\n') {
      curToken.lineno++;
    }
    getNextChar();
  }
}

auto Parser::parseId(Token::TokenType type) noexcept -> void {
  std::string::const_iterator start = nextCharPtr - 1;
  while (isalnum(curChar) || curChar == '_') {
    getNextChar();
  }

  curToken.content = std::string_view{start, nextCharPtr - 1};
  if (type != Token::TokenType::UNKNOWN) {
    curToken.type = type;
  } else {
    curToken.type = idOrToken(curToken.content);
  }
}

auto Parser::parseUnicodeCodePoint(std::vector<uint8_t> &buf) -> void {
  int32_t value = 0;
  uint8_t digit = 0;
  for (int i = 0; i < 4; i++) {
    getNextChar();
    if (curChar == '\0') {
      throw LexException("unterminated unicode!");
    }
    if (curChar >= '0' && curChar <= '9') {
      digit = curChar - '0';
    } else if (curChar >= 'a' && curChar <= 'z') {
      digit = curChar - 'a'+10;
    } else if (curChar >= 'A' && curChar <= 'Z') {
      digit = curChar - 'A'+10;
    } else {
      throw LexException("invalid unicode!");
    }

    value = value << 4 | digit;
  }

  auto size = getByteNumOfEncodeUtf8(value);
  buf.resize(size);
  
}